class BaseFitnessCalculator:
    """基础计算器类"""

    @staticmethod
    def find_age_group(ages, target_age):
        """查找匹配的年龄组"""
        sorted_ages = sorted(ages)
        for age in sorted_ages:
            if age >= target_age:
                return age
        return sorted_ages[-1]

    @staticmethod
    def parse_time(time_str):
        """解析时间字符串为秒数"""
        try:
            if not time_str:
                return None

            normalized_time = time_str.replace('：', ':')
            parts = normalized_time.split(':')

            if len(parts) == 2:
                minutes, seconds = map(int, parts)
                if minutes >= 0 and 0 <= seconds < 60:
                    return minutes * 60 + seconds
            elif len(parts) == 1:
                # 只有秒数的情况
                seconds = float(parts[0])
                if seconds >= 0:
                    return seconds

            return None
        except:
            return None

    @staticmethod
    def calculate_bmi(height, weight):
        """计算BMI"""
        if not height or not weight:
            return 0
        height_in_meter = height / 100
        return round(weight / (height_in_meter * height_in_meter), 2)


class MaleFitnessCalculator(BaseFitnessCalculator):
    """男生体能计算器"""

    # 评分表数据
    SCORE_TABLES = {
        '3000米': {
            'type': 'time',
            'data': {
                24: {
                    'thresholds': [690, 715, 730, 745, 760, 775, 790, 810, 815, 816],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                27: {
                    'thresholds': [702, 727, 742, 757, 772, 787, 802, 822, 827, 828],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                30: {
                    'thresholds': [738, 763, 778, 793, 808, 823, 838, 858, 863, 864],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                33: {
                    'thresholds': [774, 799, 814, 829, 844, 859, 874, 884, 895, 896],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                36: {
                    'thresholds': [810, 835, 850, 865, 880, 895, 910, 930, 935, 936],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                39: {
                    'thresholds': [846, 871, 886, 901, 916, 931, 945, 950, 955, 956],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                42: {
                    'thresholds': [888, 913, 928, 943, 958, 973, 988, 1008, 1013, 1014],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                45: {
                    'thresholds': [930, 955, 970, 985, 1000, 1015, 1030, 1050, 1055, 1056],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                48: {
                    'thresholds': [972, 997, 1012, 1027, 1042, 1057, 1072, 1092, 1097, 1098],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                51: {
                    'thresholds': [1014, 1039, 1054, 1069, 1088, 1099, 1114, 1134, 1139, 1140],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                54: {
                    'thresholds': [1056, 1081, 1096, 1111, 1130, 1141, 1156, 1176, 1181, 1182],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                57: {
                    'thresholds': [1098, 1123, 1138, 1153, 1172, 1183, 1198, 1218, 1223, 1224],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                59: {
                    'thresholds': [1140, 1165, 1180, 1195, 1214, 1225, 1240, 1260, 1265, 1266],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                }
            }
        },
        '蛇形跑': {
            'type': 'time',
            'data': {
                24: {
                    'thresholds': [18.1, 18.7, 19.0, 19.2, 19.5, 19.7, 19.9, 20.1, 20.4, 20.5],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                27: {
                    'thresholds': [18.3, 18.9, 19.3, 19.5, 19.8, 20.0, 20.2, 20.4, 20.8, 20.9],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                30: {
                    'thresholds': [18.5, 19.1, 19.5, 19.7, 20.0, 20.2, 20.4, 20.7, 21.1, 21.2],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                33: {
                    'thresholds': [18.7, 19.3, 19.7, 19.9, 20.1, 20.3, 20.7, 21.1, 21.3, 21.4],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                36: {
                    'thresholds': [18.9, 19.5, 19.9, 20.1, 20.2, 20.5, 20.9, 21.3, 21.7, 21.8],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                39: {
                    'thresholds': [19.1, 19.8, 20.1, 20.2, 20.5, 20.8, 21.1, 21.4, 21.8, 21.9],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                42: {
                    'thresholds': [19.3, 20.0, 20.2, 20.4, 20.6, 21.0, 21.2, 21.6, 22.3, 22.4],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                45: {
                    'thresholds': [19.5, 20.2, 20.4, 20.6, 20.7, 21.3, 21.5, 21.8, 22.4, 22.5],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                48: {
                    'thresholds': [19.7, 20.4, 20.6, 20.8, 20.9, 21.5, 21.7, 22.0, 22.6, 22.7],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                51: {
                    'thresholds': [19.9, 20.7, 20.9, 21.1, 21.3, 21.7, 21.8, 22.4, 22.8, 22.9],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                54: {
                    'thresholds': [20.6, 20.9, 21.1, 21.4, 21.7, 22.0, 22.2, 22.8, 23.4, 23.5],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                57: {
                    'thresholds': [21.1, 21.3, 21.5, 22.0, 22.2, 22.5, 23.3, 23.5, 23.8, 23.9],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                59: {
                    'thresholds': [21.3, 21.7, 22.0, 22.3, 22.7, 23.0, 23.7, 24.0, 24.5, 24.6],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                }
            }
        },
        '仰卧卷腹': {
            'type': 'count',
            'data': {
                24: {
                    'thresholds': [33, 34, 36, 42, 44, 50, 57, 65, 74, 85],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                27: {
                    'thresholds': [31, 32, 35, 40, 42, 46, 53, 61, 70, 81],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                30: {
                    'thresholds': [30, 31, 33, 38, 41, 44, 51, 59, 68, 79],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                33: {
                    'thresholds': [29, 30, 32, 37, 40, 42, 49, 57, 66, 77],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                36: {
                    'thresholds': [26, 27, 30, 35, 37, 40, 47, 55, 64, 75],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                39: {
                    'thresholds': [24, 25, 28, 33, 36, 39, 46, 54, 63, 74],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                42: {
                    'thresholds': [22, 23, 26, 29, 32, 36, 40, 48, 57, 66],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                45: {
                    'thresholds': [21, 22, 24, 27, 30, 34, 39, 47, 56, 65],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                48: {
                    'thresholds': [19, 20, 23, 26, 29, 33, 37, 45, 54, 63],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                51: {
                    'thresholds': [18, 19, 22, 25, 27, 31, 34, 42, 51, 60],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                54: {
                    'thresholds': [17, 18, 21, 24, 26, 29, 33, 41, 50, 59],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                57: {
                    'thresholds': [16, 17, 19, 22, 24, 27, 31, 39, 48, 57],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                59: {
                    'thresholds': [13, 14, 17, 20, 23, 26, 30, 38, 47, 55],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                }
            }
        },
        '引体向上': {
            'type': 'count',
            'data': {
                24: {
                    'thresholds': [10, 11, 12, 14, 15, 18, 21, 24, 27, 30],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                27: {
                    'thresholds': [9, 10, 11, 13, 14, 16, 19, 22, 25, 28],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                30: {
                    'thresholds': [8, 9, 10, 11, 12, 14, 17, 20, 23, 26],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                33: {
                    'thresholds': [7, 8, 9, 10, 11, 13, 15, 17, 20, 23],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                36: {
                    'thresholds': [6, 7, 8, 9, 10, 11, 12, 14, 17, 20],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                39: {
                    'thresholds': [5, 6, 7, 8, 9, 10, 11, 13, 15, 17],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                42: {
                    'thresholds': [27, 28, 29, 34, 39, 45, 51, 57, 65, 73],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                45: {
                    'thresholds': [26, 27, 28, 31, 37, 43, 49, 55, 62, 69],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                48: {
                    'thresholds': [23, 24, 25, 30, 36, 42, 48, 54, 61, 68],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                51: {
                    'thresholds': [21, 22, 23, 28, 34, 40, 46, 52, 59, 66],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                54: {
                    'thresholds': [18, 19, 20, 26, 32, 38, 44, 51, 58, 65],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                57: {
                    'thresholds': [16, 17, 18, 24, 30, 36, 42, 48, 55, 62],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                59: {
                    'thresholds': [10, 11, 12, 15, 20, 25, 29, 34, 39, 44],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                }
            }
        }
    }

    # BMI评分规则
    BMI_RULES = {
        'type': 'value',
        'data': {
            24: {
                'thresholds': [18.5, 25.9, 1000],
                'scores': ['不及格', '及格', '不及格']
            },
            29: {
                'thresholds': [18.5, 26.9, 1000],
                'scores': ['不及格', '及格', '不及格']
            },
            39: {
                'thresholds': [18.5, 27.9, 1000],
                'scores': ['不及格', '及格', '不及格']
            },
            49: {
                'thresholds': [18.5, 28.9, 1000],
                'scores': ['不及格', '及格', '不及格']
            },
            59: {
                'thresholds': [18.5, 29.4, 1000],
                'scores': ['不及格', '及格', '不及格']
            }
        }
    }

    # 等级评定规则
    GRADE_RULES = {
        '3000米': {
            'thresholds': [60, 80, 90],
            'grades': ['不及格', '及格', '良好', '优秀']
        },
        '蛇形跑': {
            'thresholds': [60, 80, 90],
            'grades': ['不及格', '及格', '良好', '优秀']
        },
        '引体向上': {
            'thresholds': [60, 80, 90],
            'grades': ['不及格', '及格', '良好', '优秀']
        },
        '仰卧卷腹': {
            'thresholds': [60, 80, 90],
            'grades': ['不及格', '及格', '良好', '优秀']
        }
    }

    TOTAL_GRADE_RULES = {
        'thresholds': [240, 320, 360],
        'grades': ['不及格', '及格', '良好', '优秀']
    }

    @staticmethod
    def calculate_bmi_grade(age, bmi):
        """计算男生BMI等级"""
        age_groups = list(MaleFitnessCalculator.BMI_RULES['data'].keys())
        matched_age = MaleFitnessCalculator.find_age_group(age_groups, age)
        rules = MaleFitnessCalculator.BMI_RULES['data'][matched_age]
        thresholds = rules['thresholds']
        scores = rules['scores']

        if bmi < thresholds[0]:
            return scores[0]
        elif bmi < thresholds[1]:
            return scores[1]
        else:
            return scores[2]

    @staticmethod
    def get_score(project, age, performance):
        """获取男生单项得分"""
        project_info = MaleFitnessCalculator.SCORE_TABLES.get(project)
        if not project_info or not project_info['data']:
            return 0

        age_groups = list(project_info['data'].keys())
        matched_age = MaleFitnessCalculator.find_age_group(age_groups, age)
        data = project_info['data'][matched_age]
        thresholds = data['thresholds']
        scores = data['scores']
        score_type = project_info['type']

        if score_type == 'time':
            # 时间类：找到第一个大于等于成绩的阈值
            for i, threshold in enumerate(thresholds):
                if performance <= threshold:
                    return scores[i]
            return scores[-1]
        elif score_type == 'count':
            # 计数类：找到第一个大于成绩的阈值
            for i, threshold in enumerate(thresholds):
                if performance < threshold:
                    return scores[i]  # 直接返回对应的分数
            return scores[-1]  # 如果成绩超过所有阈值，返回最高分
        else:
            return 0

    @staticmethod
    def get_grade(project, score):
        """获取男生单项等级"""
        rules = MaleFitnessCalculator.GRADE_RULES.get(project)
        if not rules:
            return ''
        thresholds = rules['thresholds']
        grades = rules['grades']

        if score < thresholds[0]:
            return grades[0]
        elif score < thresholds[1]:
            return grades[1]
        elif score < thresholds[2]:
            return grades[2]
        else:
            return grades[3]

    @staticmethod
    def get_total_grade(total_score,individual_scores=None):
        """获取男生总等级"""
        # 如果有单项得分数据，检查是否有项目不及格
        if individual_scores:
            for score in individual_scores.values():
                if score < 60:
                    return '不及格'
        thresholds = MaleFitnessCalculator.TOTAL_GRADE_RULES['thresholds']
        grades = MaleFitnessCalculator.TOTAL_GRADE_RULES['grades']

        if total_score < thresholds[0]:
            return grades[0]
        elif total_score < thresholds[1]:
            return grades[1]
        elif total_score < thresholds[2]:
            return grades[2]
        else:
            return grades[3]


class FemaleFitnessCalculator(BaseFitnessCalculator):
    """女生体能计算器"""

    # 女生评分表数据
    SCORE_TABLES = {
        '3000米': {
            'type': 'time',
            'data': {
                24: {
                    'thresholds': [840, 865, 880, 895, 910, 925, 940, 960, 965, 966],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                27: {
                    'thresholds': [853, 878, 893, 908, 923, 938, 953, 973, 978, 979],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                30: {
                    'thresholds': [892, 917, 932, 947, 962, 977, 992, 1022, 1027, 1028],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                33: {
                    'thresholds': [931, 956, 971, 986, 1001, 1016, 1031, 1051, 1056, 1057],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                36: {
                    'thresholds': [970, 995, 1010, 1025, 1040, 1065, 1080, 1100, 1105, 1106],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                39: {
                    'thresholds': [1006, 1034, 1049, 1066, 1079, 1104, 1119, 1139, 1144, 1145],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                42: {
                    'thresholds': [1038, 1073, 1088, 1103, 1118, 1133, 1148, 1168, 1173, 1174],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                45: {
                    'thresholds': [1087, 1112, 1127, 1142, 1157, 1172, 1187, 1207, 1212, 1213],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                48: {
                    'thresholds': [1126, 1151, 1166, 1181, 1196, 1211, 1226, 1246, 1251, 1252],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                51: {
                    'thresholds': [1165, 1190, 1205, 1220, 1235, 1250, 1265, 1285, 1290, 1291],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                54: {
                    'thresholds': [1204, 1229, 1244, 1259, 1274, 1269, 1304, 1324, 1329, 1330],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                57: {
                    'thresholds': [1243, 1268, 1283, 1298, 1313, 1328, 1343, 1363, 1368, 1369],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                59: {
                    'thresholds': [1282, 1307, 1322, 1337, 1342, 1367, 1382, 1402, 1407, 1408],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                }
            }
        },

        '蛇形跑': {
            'type': 'time',
            'data': {
                24: {
                    'thresholds': [20.0, 20.4, 20.9, 21.1, 21.3, 21.6, 21.7, 21.9, 22.2, 22.3],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                27: {
                    'thresholds': [20.3, 20.7, 21.2, 21.4, 21.6, 21.9, 22.0, 22.2, 22.5, 22.6],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                30: {
                    'thresholds': [20.6, 21.0, 21.5, 21.7, 21.9, 22.2, 22.3, 22.5, 22.8, 22.9],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                33: {
                    'thresholds': [20.9, 21.3, 21.8, 22.0, 22.2, 22.5, 22.6, 22.8, 23.1, 23.2],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                36: {
                    'thresholds': [21.2, 21.6, 22.1, 22.3, 22.5, 22.8, 22.9, 23.1, 23.4, 23.5],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                39: {
                    'thresholds': [21.5, 21.9, 22.4, 22.6, 22.8, 23.1, 23.2, 23.4, 23.7, 23.8],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                42: {
                    'thresholds': [21.8, 22.2, 22.7, 22.9, 23.1, 23.4, 23.5, 23.7, 24.0, 24.1],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                45: {
                    'thresholds': [22.1, 22.5, 23.0, 23.2, 23.4, 23.7, 23.8, 24.0, 24.3, 24.4],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                48: {
                    'thresholds': [22.4, 22.8, 23.3, 23.5, 23.7, 24.0, 24.1, 24.3, 24.6, 24.7],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                51: {
                    'thresholds': [22.7, 23.1, 23.6, 23.8, 24.0, 24.3, 24.4, 24.6, 24.9, 25.0],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                54: {
                    'thresholds': [23.0, 23.4, 23.9, 24.1, 24.3, 24.6, 24.7, 24.9, 25.2, 25.3],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                57: {
                    'thresholds': [23.3, 23.7, 24.2, 24.4, 24.6, 24.9, 25.0, 25.2, 25.5, 25.6],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                },
                59: {
                    'thresholds': [23.6, 24.0, 24.5, 24.7, 24.9, 25.2, 25.3, 25.5, 25.8, 25.9],
                    'scores': [100, 95, 90, 85, 80, 75, 70, 65, 60, 0]
                }
            }
        },

        '仰卧卷腹': {
            'type': 'count',
            'data': {
                24: {
                    'thresholds': [27, 28, 30, 34, 38, 42, 46, 51, 58, 65],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                27: {
                    'thresholds': [26, 27, 29, 33, 36, 40, 44, 49, 56, 63],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                30: {
                    'thresholds': [24, 25, 27, 31, 34, 39, 43, 48, 55, 62],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                33: {
                    'thresholds': [23, 24, 26, 30, 33, 38, 42, 47, 54, 61],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                36: {
                    'thresholds': [22, 23, 25, 29, 32, 36, 40, 45, 52, 59],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                39: {
                    'thresholds': [20, 21, 23, 27, 30, 35, 39, 44, 51, 58],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                42: {
                    'thresholds': [18, 19, 21, 25, 28, 32, 36, 41, 48, 55],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                45: {
                    'thresholds': [17, 18, 20, 24, 27, 31, 35, 40, 47, 54],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                48: {
                    'thresholds': [15, 16, 18, 22, 25, 30, 34, 39, 46, 53],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                51: {
                    'thresholds': [14, 15, 17, 21, 24, 29, 33, 38, 45, 52],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                54: {
                    'thresholds': [13, 14, 16, 20, 23, 28, 32, 37, 44, 51],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                57: {
                    'thresholds': [12, 13, 15, 19, 22, 27, 31, 36, 43, 50],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                59: {
                    'thresholds': [11, 12, 14, 18, 21, 26, 30, 35, 43, 49],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                }
            }
        },

        '引体向上': {
            'type': 'count',
            'data': {
                24: {
                    'thresholds': [35, 36, 42, 46, 50, 54, 58, 62, 66, 70],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                27: {
                    'thresholds': [34, 35, 39, 43, 47, 51, 55, 59, 62, 65],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                30: {
                    'thresholds': [32, 33, 37, 41, 47, 51, 53, 57, 60, 63],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                33: {
                    'thresholds': [29, 30, 34, 38, 42, 46, 50, 54, 57, 60],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                36: {
                    'thresholds': [26, 27, 31, 35, 39, 43, 47, 51, 54, 57],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                39: {
                    'thresholds': [23, 24, 28, 32, 36, 40, 44, 48, 51, 54],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                42: {
                    'thresholds': [13, 14, 15, 16, 17, 19, 21, 24, 27, 30],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                45: {
                    'thresholds': [12, 13, 14, 15, 16, 17, 19, 21, 24, 27],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                48: {
                    'thresholds': [11, 12, 13, 14, 15, 16, 17, 19, 21, 24],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                51: {
                    'thresholds': [9, 10, 11, 12, 14, 15, 16, 17, 19, 21],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                54: {
                    'thresholds': [8, 9, 10, 11, 12, 14, 15, 16, 17, 19],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                57: {
                    'thresholds': [7, 8, 9, 10, 11, 12, 14, 15, 16, 17],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                },
                59: {
                    'thresholds': [3, 4, 5, 7, 10, 11, 12, 14, 15, 16],
                    'scores': [0, 0, 60, 65, 70, 75, 80, 85, 90, 95, 100]
                }
            }
        }
    }

    # 女生BMI评分规则
    BMI_RULES = {
        'type': 'value',
        'data': {
            24: {
                'thresholds': [18.5, 25.9, 1000],
                'scores': ['不及格', '及格', '不及格']
            },
            29: {
                'thresholds': [18.5, 26.9, 1000],
                'scores': ['不及格', '及格', '不及格']
            },
            39: {
                'thresholds': [18.5, 27.9, 1000],
                'scores': ['不及格', '及格', '不及格']
            },
            49: {
                'thresholds': [18.5, 28.9, 1000],
                'scores': ['不及格', '及格', '不及格']
            },
            59: {
                'thresholds': [18.5, 29.4, 1000],
                'scores': ['不及格', '及格', '不及格']
            }
        }
    }

    # 等级评定规则（女生）
    GRADE_RULES = {
        '3000米': {
            'thresholds': [60, 80, 90],
            'grades': ['不及格', '及格', '良好', '优秀']
        },
        '蛇形跑': {
            'thresholds': [60, 80, 90],
            'grades': ['不及格', '及格', '良好', '优秀']
        },
        '引体向上': {
            'thresholds': [60, 80, 90],
            'grades': ['不及格', '及格', '良好', '优秀']
        },
        '仰卧卷腹': {
            'thresholds': [60, 80, 90],
            'grades': ['不及格', '及格', '良好', '优秀']
        }
    }

    TOTAL_GRADE_RULES = {
        'thresholds': [240, 320, 360],
        'grades': ['不及格', '及格', '良好', '优秀']
    }

    @staticmethod
    def calculate_bmi_grade(age, bmi):
        """计算女生BMI等级"""
        age_groups = list(FemaleFitnessCalculator.BMI_RULES['data'].keys())
        matched_age = FemaleFitnessCalculator.find_age_group(age_groups, age)
        rules = FemaleFitnessCalculator.BMI_RULES['data'][matched_age]
        thresholds = rules['thresholds']
        scores = rules['scores']

        if bmi < thresholds[0]:
            return scores[0]
        elif bmi < thresholds[1]:
            return scores[1]
        else:
            return scores[2]

    @staticmethod
    def get_score(project, age, performance):
        """获取女生单项得分 - 修正后的逻辑"""
        project_info = FemaleFitnessCalculator.SCORE_TABLES.get(project)
        if not project_info or not project_info['data']:
            return 0

        age_groups = list(project_info['data'].keys())
        matched_age = FemaleFitnessCalculator.find_age_group(age_groups, age)
        data = project_info['data'][matched_age]
        thresholds = data['thresholds']
        scores = data['scores']
        score_type = project_info['type']

        if score_type == 'time':
            # 时间类：找到第一个大于等于成绩的阈值
            for i, threshold in enumerate(thresholds):
                if performance <= threshold:
                    return scores[i]
            return scores[-1]
        elif score_type == 'count':
            # 计数类：找到第一个大于成绩的阈值
            for i, threshold in enumerate(thresholds):
                if performance < threshold:
                    return scores[i]  # 直接返回对应的分数
            return scores[-1]  # 如果成绩超过所有阈值，返回最高分
        else:
            return 0

    @staticmethod
    def get_grade(project, score):
        """获取女生单项等级"""
        rules = FemaleFitnessCalculator.GRADE_RULES.get(project)
        if not rules:
            return ''
        thresholds = rules['thresholds']
        grades = rules['grades']

        if score < thresholds[0]:
            return grades[0]
        elif score < thresholds[1]:
            return grades[1]
        elif score < thresholds[2]:
            return grades[2]
        else:
            return grades[3]

    @staticmethod
    def get_total_grade(total_score,individual_scores=None):
        """获取女生总等级"""
        """获取女生总等级 - 添加单项不及格判定"""
        # 如果有单项得分数据，检查是否有项目不及格
        if individual_scores:
            for score in individual_scores.values():
                if score < 60:
                    return '不及格'
        thresholds = FemaleFitnessCalculator.TOTAL_GRADE_RULES['thresholds']
        grades = FemaleFitnessCalculator.TOTAL_GRADE_RULES['grades']

        if total_score < thresholds[0]:
            return grades[0]
        elif total_score < thresholds[1]:
            return grades[1]
        elif total_score < thresholds[2]:
            return grades[2]
        else:
            return grades[3]